﻿//Copyright (C) <2013>  <jonathan cleeve norton> All Rights Reserved 
//Contact jon.norton@fin-plus.co.uk website <http://www.fin-plus.co.uk/>
using System.Collections.Generic;
using System;
using System.Text;
using System.Xml;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Forms;
using System.Text.RegularExpressions;
using FinPlusAssembler;
using FinPlusInterfaces;

namespace FinPlusCompView
{
    public partial class FinPlusTemplateMap : FinPlusControl
    {
        [State(Test = true)]
        public override bool IsValid { get; set; }
        [State(Test = true)]
        public override string TestString { get { return Adapter.ToString(); } }
        [State(Save = true)]
        public new double Height { get { return base.Height; } set { base.Height = value; } }
        [State(Save = true)]
        public new double Width { get { return base.Width; } set { base.Width = value; } }
        [State(Save = true, Test= true)]
        public string ViewFilePath { get { return _viewPath; } set { tClientFilePath.Text = _viewPath = value; } }
        [State(Save = true, Test = true)]
        public string ServiceFilePath { get { return _servicePath; } set { tServiceFilePath.Text = _servicePath = value; } }
        [State(Save = true, Test = true)]
        public string ConfigSelection { get { return _templateSelection; } set { templateSelection.SelectedValue = _templateSelection = value; } }
        [State(Save = true, Test = true)]
        public string CompViewState { get { return GetCompViewState(); } set { SetCompViewState(value); } }

        private enum Params { Injected, ServiceType, ServiceName, TemplateType, Template, Component };
        private IPods _comps;
        private IPod _compParent;
        private readonly IDictionary<string, IPod> _constCache, _methodCache, _propertyCache;
        private string _viewPath, _servicePath, _compViewPath, _templateSelection;
        private readonly IList<string> _links;

        //construct
        public FinPlusTemplateMap()
        {
            InitializeComponent();

            _constCache = new Dictionary<string, IPod>();
            _methodCache = new Dictionary<string, IPod>();
            _propertyCache = new Dictionary<string, IPod>();
            _links = new List<string>();
            IsValid = true;
        }

        //common control interface
        public override void CmdExecute(IPod command)
        {
            try
            {
                CmdCapture(command);

                switch ((Cmds)Enum.Parse(typeof(Cmds), command.Name, true))
                {
                    case Cmds.Refresh: Refresh(); break;
                    case Cmds.Clear: Clear(); break;
                    case Cmds.Play: Play(); break;
                    case Cmds.ViewFile: tClientFilePath.Text = _viewPath = command["Tag"].ToString(); break;
                    case Cmds.ServiceFile: tServiceFilePath.Text = _servicePath = command["Tag"].ToString(); break;
                    case Cmds.ServicePath: SelectPath(Cmds.ServiceFile); break;
                    case Cmds.ViewPath: SelectPath(Cmds.ViewFile); break;
                    case Cmds.Selection: Selection(); break;
                    default: throw new Exception(string.Format("cmd not recognised {0}", command.Name));
                }
            }
            catch (CmdExecuteException e)
            {
                IsValid = Level.Warning.Log(Id, Config, e.Message, e);
            }
        }

        public override void Dispose()  
        {
              DI.Dispose(LinkedId);
        }

        //private
        private async void Refresh()
        {
            var wait = new FinPlusWait(compGrid, "Refreshing...");

            try
            {
                _comps = IOC.New<IPods>();
                var configNames = new List<string>();

                await Task.Run(() =>
                {
                    LoadTemplates(_comps, configNames, new string[]{ _viewPath, _servicePath}, new string[]{"*.view", "*.service"});
                });

                ShowComps(_comps);

                templateSelection.ItemsSource = configNames;
            }
            catch (Exception e)
            {
                IsValid = Level.Warning.Log(Id, Config, e.Message, e);
            }

            wait.Dispose();
        }

        private async void Play()
        {
            var wait = new FinPlusWait(mapGrid, "Loading...");

            try
            {
                mapGrid.Children.Clear();
                _links.Clear();
                var doc = new XmlDocument();

                await Task.Run(() => GetComponent(_comps, doc, null, _templateSelection, _templateSelection));
   
                mapGrid.Children.Add(new FinPlusTemplateTree() { Id = "CompMap", xmlDocument = doc });
            }
            catch (Exception e)
            {
                IsValid = Level.Warning.Log(Id, Config, e.Message, e);
            }

            wait.Dispose();
        }

        private void Clear()
        {
            _comps = null;
            compGrid.Children.Clear();
            mapGrid.Children.Clear();
        }

        private void ShowComps(IPods pods)
        {
            var path = Paths.Values["FolderSubViews"] + "Templates.view";
            _compParent = IOC.New<IPods>(path).Construct("Templates", Env, new object[,] { { "Data", IOC.New<IDPods>(pods) } });
            SetCompViewState(_compViewPath);

            compGrid.Children.Clear();
            compGrid.Children.Add((FinPlusGroupGrid)_compParent.Object);
        }

        private void GetComponent(IPods pods, XmlDocument doc, XmlNode parentNode, string name, string template = null)
        {
            if (_comps == null)
                return;

            if(template == null) 
                template = name;

            var res = _comps.Values.Where(f => f[BeanField.Name.ToString()].Equals(name) && f[Params.Template.ToString()].Equals(template));
            if (res.Count() < 1) 
                return;

            var pod = res.First();
            var node = doc.CreateNode(XmlNodeType.Element, name, null);
            var typeName = pod[PodField.Type.ToString()].ToString();
            node.Attributes.Append(doc.Attribute("TypeOf", string.Format("({0})", typeName)));
            node.Attributes.Append(doc.Attribute("Base", string.Format("({0})", pod.Type.BaseType.Name)));
            
            if (parentNode != null)
                parentNode.AppendChild(node);
            else
                doc.AppendChild(node);
            
            AddConst(doc, node, pod);
            AddMethods(doc, node, pod);
            AddPropertys(doc, node, pod);
            AddLinks(doc, node, pods, pod, name, template);
        }

        private void AddConst(XmlDocument doc, XmlNode parentNode, IPod pod)
        {
            var Type = pod[PodField.Type.ToString()].ToString();
            IPod cons;

            if (!_constCache.ContainsKey(Type))
                _constCache.Add(Type, cons = pod.GetConst());
            else
                cons = _constCache[Type];

            var node = doc.CreateNode(XmlNodeType.Element, "Const", null);
            var childNode = doc.CreateNode(XmlNodeType.Element, "List", null);

            foreach (var con in cons)
                if (!con.Name.EnumIsDefined<PodField>())
                    childNode.Attributes.Append(doc.Attribute(con.Name, con.ToString()));

            node.AppendChild(childNode);
            parentNode.AppendChild(node);
        }

        private void AddMethods(XmlDocument doc, XmlNode parentNode, IPod pod)
        {
            var Type = pod[PodField.Type.ToString()].ToString();
            IPod methods;

            if (!_methodCache.ContainsKey(Type))
                _methodCache.Add(Type, methods = pod.GetMethods());
            else
                methods = _methodCache[Type];
                
            var node = doc.CreateNode(XmlNodeType.Element, "Methods", null);
            var childNode = doc.CreateNode(XmlNodeType.Element, "List", null);

            foreach (var method in methods)
                if (!method.Name.EnumIsDefined<PodField>())
                    childNode.Attributes.Append(doc.Attribute(method.Name, method.ToString()));
                
            node.AppendChild(childNode);
            parentNode.AppendChild(node);
        }

        private void AddPropertys(XmlDocument doc, XmlNode parentNode, IPod pod)
        {
            var Type = pod[PodField.Type.ToString()].ToString();
            IPod propertys;

            if (!_propertyCache.ContainsKey(Type))
                _propertyCache.Add(Type, propertys = pod.GetProperties());
            else
                propertys = _propertyCache[Type];
 
            var node = doc.CreateNode(XmlNodeType.Element, "Properties", null);
            var childNode = doc.CreateNode(XmlNodeType.Element, "List", null);
        
            foreach (var property in propertys)
                if (!property.Name.EnumIsDefined<PodField>())
                    childNode.Attributes.Append(doc.Attribute(property.Name, property.ToString()));

            node.AppendChild(childNode);
            parentNode.AppendChild(node);
        }

        private void AddLinks(XmlDocument doc, XmlNode parentNode, IPods pods, IPod pod, string name, string config)
        {
            var node = doc.CreateNode(XmlNodeType.Element, Params.Injected.ToString(), null);
            parentNode.AppendChild(node);

            if (!string.IsNullOrEmpty(pod[Params.ServiceType.ToString()].ToString()))
                 GetComponent(pods, doc, node, pod[Params.ServiceType.ToString()].ToString());
            else
                foreach (var injected in pod.Get(Params.Injected.ToString()).ToString().Split(','))
                    if(!string.IsNullOrEmpty(injected))
                        GetComponent(pods, doc, node, injected.Split('.')[1], config);
        }

        private void LoadTemplates(IPods templates, IList<string> configNames, string[] folders, string[] extensions)
        {
            foreach (var folder in folders)
                if(folder !=null)
                    foreach (var extension in extensions)
                        foreach (var filePath in Directory.GetFiles(folder, extension))
                            LoadTemplate(templates, configNames, filePath, System.IO.Path.GetFileName(filePath));
        }

        private void LoadTemplate(IPods templates, IList<string> configNames, string filePath, string config)
        {
            var pods = IOC.New<IPods>(filePath);
            var res = System.IO.Path.GetFileName(filePath).Split('.');
            configNames.Add(res[0]);

            foreach (var pod in pods.Values)
            {
                if (pod.Name.Equals("VersionControl"))
                    continue;
                
                var comp = IOC.New<IPod>(pod[PodField.Type.ToString()].ToString(), Id, User, templates.NextKey());
                comp[BeanField.Name.ToString()] = pod[PodField.Id.ToString()];
                comp[Params.Injected.ToString()] =  FindLinks(pod);
                comp[Params.ServiceType.ToString()] = pod[Params.ServiceType.ToString()] ?? string.Empty;
                comp[Params.ServiceName.ToString()] = pod[Params.ServiceName.ToString()] ?? string.Empty;
                comp[Params.Template.ToString()] = res[0];
                comp[Params.TemplateType.ToString()] = res[1].ToLower();
                comp[Params.Component.ToString()] = pod;
                comp.Type = IOC.FindType(comp.Name);
                templates.Add(comp);
            }
        }

        private string FindLinks(IPod pod)
        {
            var links = new StringBuilder();
            if(!pod.Name.Equals("VersionControl"))
                foreach (var bean in pod)
                    if(!bean.Name.EnumIsDefined<PodField>())
                        foreach (var str in Regex.Split(bean.ToString(), @"[^a-zA-Z0-9_.]+"))
                            if (str.Contains("."))
                            {
                                links.Append(str);
                                links.Append(',');
                            }

            return links.ToString().TrimEnd(',');
        }

        private string GetCompViewState()
        {
            if(_compParent == null) 
                return string.Empty;

            if(string.IsNullOrEmpty(_compViewPath))
                _compViewPath = Paths.Values["FolderSubViews"] + "Templates";

            _compParent.ExtractState(Environment.UserName).ToXmlDoc().Save(_compViewPath); 
            return _compViewPath;
        }

        private void SetCompViewState(string path)
        {
            _compViewPath = path;
            if (!string.IsNullOrEmpty(path))
                _compParent.InjectState(path);
        }

        private void Selection() { _templateSelection = templateSelection.SelectedItem.ToString();}

        private void SelectPath(Cmds command)
        {
            var d = new FolderBrowserDialog();
            var res = d.ShowDialog();

            if (res == DialogResult.OK)
                CmdRouter(command.ToString(), d.SelectedPath);
        }

        //cmds
        private enum Cmds { Refresh, Clear, Play, Selection, ViewPath, ServicePath, ViewFile, ServiceFile }

        private void Template_Selected(object s, RoutedEventArgs a) { CmdRouter(Cmds.Selection.ToString()); }
    }
}





























































































//Copyright2013<jnrton>AllRightsReserved 
//Contact j.nrton@finpus